/*
 * Copyright (c) 1994, 2013, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 *
 */

package java.io;

/**
 * 这个抽象类是所有表示字节输入流的类的超类。
 *
 * <p> 需要定义 <code>InputStream</code> 子类的应用程序必须始终提供返回下一个输入字节的方法。
 *
 * @author  Arthur van Hoff
 * @see     java.io.BufferedInputStream
 * @see     java.io.ByteArrayInputStream
 * @see     java.io.DataInputStream
 * @see     java.io.FilterInputStream
 * @see     java.io.InputStream#read()
 * @see     java.io.OutputStream
 * @see     java.io.PushbackInputStream
 * @since   JDK1.0
 */
public abstract class InputStream implements Closeable {

    // MAX_SKIP_BUFFER_SIZE 用于确定跳过时要使用的最大缓冲区大小
    private static final int MAX_SKIP_BUFFER_SIZE = 2048;

    /**
     * 从输入流读取下一个字节的数据。字节值作为 <code>int</code> 返回，范围为 <code>0</code> 到
     * <code>255</code>。如果由于已到达流末尾而没有字节可用，则返回 <code>-1</code>。此方法会阻塞，直到输入数据可用、检测到流末尾或抛出异常。
     *
     * <p> 子类必须提供此方法的实现。
     *
     * @return     下一个字节的数据，如果已到达流末尾则为 <code>-1</code>
     * @exception  IOException  如果发生 I/O 错误
     */
    public abstract int read() throws IOException;

    /**
     * 从输入流读取一些字节数并将它们存储到缓冲区数组 <code>b</code> 中。实际读取的字节数作为整数返回。
     * 此方法会阻塞，直到输入数据可用、文件结束被检测到或抛出异常。
     *
     * <p> 如果 <code>b</code> 的长度为零，则不读取字节并返回 <code>0</code>；
     * 否则，会尝试读取至少一个字节。如果由于流在文件末尾而没有字节可用，则返回 <code>-1</code>；
     * 否则，至少读取一个字节并存储到 <code>b</code> 中。
     *
     * <p> 第一个读取的字节存储在元素 <code>b[0]</code> 中，下一个存储在 <code>b[1]</code> 中，依此类推。
     * 读取的字节数最多等于 <code>b</code> 的长度。设 <i>k</i> 为实际读取的字节数；
     * 这些字节将存储在元素 <code>b[0]</code> 到 <code>b[</code><i>k</i><code>-1]</code> 中，
     * 留下元素 <code>b[</code><i>k</i><code>]</code> 到 <code>b[b.length-1]</code> 不受影响。
     *
     * <p> <code>InputStream</code> 类的 <code>read(b)</code> 方法具有与 <pre><code> read(b, 0, b.length) </code></pre> 相同的效果
     *
     * @param      b   要读取数据的缓冲区
     * @return     读入缓冲区的总字节数，如果由于已到达流末尾而没有更多数据，则为 <code>-1</code>
     * @exception  IOException  如果由于除文件末尾之外的任何原因无法读取第一个字节，如果输入流已关闭，
     * 或者如果发生其他 I/O 错误
     * @exception  NullPointerException  如果 <code>b</code> 为 <code>null</code>
     * @see        java.io.InputStream#read(byte[], int, int)
     */
    public int read(byte b[]) throws IOException {
        return read(b, 0, b.length);
    }

    /**
     * 从输入流中读取最多 <code>len</code> 字节的数据到字节数组中。会尝试读取尽可能多的
     * <code>len</code> 字节，但可能读取更少的数量。实际读取的字节数作为整数返回。
     *
     * <p> 此方法会阻塞，直到输入数据可用、检测到文件结束或抛出异常。
     *
     * <p> 如果 <code>len</code> 为零，则不读取字节并返回 <code>0</code>；
     * 否则，会尝试读取至少一个字节。如果由于流在文件末尾而没有字节可用，则返回 <code>-1</code>；
     * 否则，至少读取一个字节并存储到 <code>b</code> 中。
     *
     * <p> 第一个读取的字节存储在元素 <code>b[off]</code> 中，下一个存储在 <code>b[off+1]</code> 中，依此类推。
     * 读取的字节数最多等于 <code>len</code>。设 <i>k</i> 为实际读取的字节数；
     * 这些字节将存储在元素 <code>b[off]</code> 到 <code>b[off+</code><i>k</i><code>-1]</code> 中，
     * 留下元素 <code>b[off+</code><i>k</i><code>]</code> 到 <code>b[off+len-1]</code> 不受影响。
     *
     * <p> 在任何情况下，元素 <code>b[0]</code> 到 <code>b[off]</code> 以及元素 <code>b[off+len]</code> 到
     * <code>b[b.length-1]</code> 都不受影响。
     *
     * <p> <code>InputStream</code> 类的 <code>read(b,</code> <code>off,</code> <code>len)</code> 方法
     * 只是重复调用 <code>read()</code> 方法。如果第一次这样的调用导致 <code>IOException</code>，
     * 则该异常从对 <code>read(b,</code> <code>off,</code> <code>len)</code> 方法的调用返回。
     * 如果对 <code>read()</code> 的任何后续调用导致 <code>IOException</code>，则捕获该异常并将其视为文件结束；
     * 直到该点读取的字节存储到 <code>b</code> 中，并返回异常发生前读取的字节数。
     * 此方法的默认实现会阻塞，直到已读取所请求的输入数据量 <code>len</code>、检测到文件结束或抛出异常。
     * 鼓励子类提供此方法的更有效实现。
     *
     * @param      b     要读取数据的缓冲区
     * @param      off   数组 <code>b</code> 中开始写入数据的起始偏移量
     * @param      len   要读取的最大字节数
     * @return     读入缓冲区的总字节数，如果由于已到达流末尾而没有更多数据，则为 <code>-1</code>
     * @exception  IOException  如果由于除文件末尾之外的任何原因无法读取第一个字节，如果输入流已关闭，
     * 或者如果发生其他 I/O 错误
     * @exception  NullPointerException  如果 <code>b</code> 为 <code>null</code>
     * @exception  IndexOutOfBoundsException  如果 <code>off</code> 为负数，<code>len</code> 为负数，
     * 或者 <code>len</code> 大于 <code>b.length - off</code>
     * @see        java.io.InputStream#read()
     */
    public int read(byte b[], int off, int len) throws IOException {
        if (b == null) {
            throw new NullPointerException();
        } else if (off < 0 || len < 0 || len > b.length - off) {
            throw new IndexOutOfBoundsException();
        } else if (len == 0) {
            return 0;
        }

        int c = read();
        if (c == -1) {
            return -1;
        }
        b[off] = (byte)c;

        int i = 1;
        try {
            for (; i < len ; i++) {
                c = read();
                if (c == -1) {
                    break;
                }
                b[off + i] = (byte)c;
            }
        } catch (IOException ee) {
        }
        return i;
    }

    /**
     * 跳过并丢弃此输入流中的 <code>n</code> 字节数据。<code>skip</code> 方法可能由于各种原因
     * 最终跳过较少数量的字节，可能为 <code>0</code>。这可能是由于多种条件造成的；
     * 在跳过 <code>n</code> 字节之前到达文件末尾只是其中一种可能性。返回实际跳过的字节数。
     * 如果 {@code n} 为负数，则 {@code InputStream} 类的 {@code skip} 方法始终返回 0，并且不跳过任何字节。
     * 子类可能会以不同方式处理负值。
     *
     * <p> 此类的 <code>skip</code> 方法创建一个字节数组，然后重复读取该数组，直到已读取 <code>n</code> 字节或已到达流末尾。
     * 鼓励子类提供此方法的更有效实现。例如，实现可能取决于查找的能力。
     *
     * @param      n   要跳过的字节数
     * @return     实际跳过的字节数
     * @exception  IOException  如果流不支持查找，或者发生其他 I/O 错误
     */
    public long skip(long n) throws IOException {

        long remaining = n;
        int nr;

        if (n <= 0) {
            return 0;
        }

        int size = (int)Math.min(MAX_SKIP_BUFFER_SIZE, remaining);
        byte[] skipBuffer = new byte[size];
        while (remaining > 0) {
            nr = read(skipBuffer, 0, (int)Math.min(size, remaining));
            if (nr < 0) {
                break;
            }
            remaining -= nr;
        }

        return n - remaining;
    }

    /**
     * 返回可以从此输入流读取（或跳过）的字节数的估计值，而不会阻塞，
     * 由下一次调用此输入流的方法决定。下一次调用可能是同一线程或另一个线程。
     * 单次读取或跳过这么多字节不会阻塞，但可能会读取或跳过更少的字节。
     *
     * <p> 请注意，虽然某些 {@code InputStream} 实现会返回流中的总字节数，但许多实现不会。
     * 使用此方法的返回值来分配旨在保存此流中所有数据的缓冲区从来都不是正确的做法。
     *
     * <p> 此方法的子类实现可能会选择抛出 {@link IOException}，
     * 如果此输入流已通过调用 {@link #close()} 方法关闭。
     *
     * <p> {@code InputStream} 类的 {@code available} 方法始终返回 {@code 0}。
     *
     * <p> 子类应覆盖此方法。
     *
     * @return     可以从此输入流读取（或跳过）而不会阻塞的字节数的估计值，
     *             或者当到达输入流末尾时为 {@code 0}
     * @exception  IOException  如果发生 I/O 错误
     */
    public int available() throws IOException {
        return 0;
    }

    /**
     * 关闭此输入流并释放与该流关联的任何系统资源。
     *
     * <p> <code>InputStream</code> 的 <code>close</code> 方法不执行任何操作。
     *
     * @exception  IOException  如果发生 I/O 错误
     */
    public void close() throws IOException {}

    /**
     * 标记此输入流中的当前位置。随后调用 <code>reset</code> 方法会将此流重新定位到最后标记的位置，
     * 以便后续读取重新读取相同的字节。
     *
     * <p> <code>readlimit</code> 参数告诉此输入流允许读取这么多字节，然后标记位置才失效。
     *
     * <p> <code>mark</code> 的一般约定是，如果方法 <code>markSupported</code> 返回 <code>true</code>，
     * 则流会以某种方式记住调用 <code>mark</code> 后读取的所有字节，并准备在调用 <code>reset</code> 方法时再次提供这些相同的字节。
     * 但是，如果在调用 <code>reset</code> 之前从流中读取了超过 <code>readlimit</code> 字节，
     * 则流不需要记住任何数据。
     *
     * <p> 标记已关闭的流不应产生任何效果。
     *
     * <p> <code>InputStream</code> 的 <code>mark</code> 方法不执行任何操作。
     *
     * @param   readlimit   在标记位置失效之前可以读取的最大字节数限制
     * @see     java.io.InputStream#reset()
     */
    public synchronized void mark(int readlimit) {}

    /**
     * 将此流重新定位到上次在此输入流上调用 <code>mark</code> 方法时的位置。
     *
     * <p> <code>reset</code> 的一般约定是：
     *
     * <ul>
     * <li> 如果方法 <code>markSupported</code> 返回 <code>true</code>，则：
     *
     *     <ul><li> 如果自创建流以来尚未调用方法 <code>mark</code>，或者自上次调用 <code>mark</code> 以来从流中读取的字节数大于上次调用时 <code>mark</code> 的参数，则可能抛出 <code>IOException</code>。
     *
     *     <li> 如果没有抛出这样的 <code>IOException</code>，则流会重置为这样一种状态，
     *     使得自最近一次调用 <code>mark</code>（或者如果尚未调用 <code>mark</code>，则自文件开始）以来读取的所有字节将重新提供给 <code>read</code> 方法的后续调用者，
     *     后面跟着在调用 <code>reset</code> 时原本将是下一个输入数据的任何字节。</ul>
     *
     * <li> 如果方法 <code>markSupported</code> 返回 <code>false</code>，则：
     *
     *     <ul><li> 对 <code>reset</code> 的调用可能会抛出 <code>IOException</code>。
     *
     *     <li> 如果没有抛出 <code>IOException</code>，则流会重置为取决于特定输入流类型及其创建方式的固定状态。
     *     将提供给 <code>read</code> 方法的后续调用者的字节取决于特定输入流类型。</ul></ul>
     *
     * <p> <code>InputStream</code> 类的 <code>reset</code> 方法除了抛出 <code>IOException</code> 之外不执行任何操作。
     *
     * @exception  IOException  如果此流未被标记或标记已失效
     * @see     java.io.InputStream#mark(int)
     * @see     java.io.IOException
     */
    public synchronized void reset() throws IOException {
        throw new IOException("mark/reset not supported");
    }

    /**
     * 测试此输入流是否支持 <code>mark</code> 和 <code>reset</code> 方法。
     * 是否支持 <code>mark</code> 和 <code>reset</code> 是特定输入流实例的不变属性。
     * <code>InputStream</code> 的 <code>markSupported</code> 方法返回 <code>false</code>。
     *
     * @return  如果此流实例支持标记和重置方法，则为 <code>true</code>；
     *          否则为 <code>false</code>
     * @see     java.io.InputStream#mark(int)
     * @see     java.io.InputStream#reset()
     */
    public boolean markSupported() {
        return false;
    }

}
